import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import cv2
import os
from PIL import Image, ImageTk
import threading
import time

class VideoCutter:
    def __init__(self, root):
        self.root = root
        self.root.title("视频切割工具")
        self.root.geometry("800x600")
        
        self.video_path = None
        self.cap = None
        self.total_frames = 0
        self.fps = 0
        self.duration = 0
        self.is_playing = False
        self.current_frame = 0
        
        self.start_time = 0
        self.end_time = 0
        
        self.setup_ui()
    
    def setup_ui(self):
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        
        top_frame = ttk.Frame(main_frame)
        top_frame.grid(row=0, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(0, 10))
        
        ttk.Button(top_frame, text="打开视频", command=self.open_video).pack(side=tk.LEFT, padx=(0, 10))
        self.file_label = ttk.Label(top_frame, text="未选择文件")
        self.file_label.pack(side=tk.LEFT)
        
        self.video_frame = ttk.Frame(main_frame)
        self.video_frame.grid(row=1, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 10))
        
        self.canvas = tk.Canvas(self.video_frame, width=640, height=360, bg="black")
        self.canvas.pack()
        
        control_frame = ttk.Frame(main_frame)
        control_frame.grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(0, 10))
        
        ttk.Button(control_frame, text="播放", command=self.play_video).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(control_frame, text="暂停", command=self.pause_video).pack(side=tk.LEFT, padx=(0, 10))
        
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Scale(control_frame, from_=0, to=100, orient=tk.HORIZONTAL,
                                     variable=self.progress_var, command=self.on_progress_change)
        self.progress_bar.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(10, 10))
        
        self.time_label = ttk.Label(control_frame, text="00:00 / 00:00")
        self.time_label.pack(side=tk.LEFT)
        
        time_frame = ttk.Frame(main_frame)
        time_frame.grid(row=3, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(0, 10))
        
        ttk.Label(time_frame, text="开始时间:").grid(row=0, column=0, sticky=tk.W)
        self.start_time_var = tk.StringVar(value="00:00:00")
        self.start_time_entry = ttk.Entry(time_frame, textvariable=self.start_time_var, width=10)
        self.start_time_entry.grid(row=0, column=1, padx=(5, 20))
        
        ttk.Label(time_frame, text="结束时间:").grid(row=0, column=2, sticky=tk.W)
        self.end_time_var = tk.StringVar(value="00:00:00")
        self.end_time_entry = ttk.Entry(time_frame, textvariable=self.end_time_var, width=10)
        self.end_time_entry.grid(row=0, column=3, padx=(5, 20))
        
        ttk.Button(time_frame, text="设为当前时间", command=self.set_current_as_start).grid(row=0, column=4, padx=(0, 10))
        ttk.Button(time_frame, text="设为当前时间", command=self.set_current_as_end).grid(row=0, column=5)
        
        bottom_frame = ttk.Frame(main_frame)
        bottom_frame.grid(row=4, column=0, columnspan=3, sticky=(tk.W, tk.E))
        
        ttk.Button(bottom_frame, text="预览片段", command=self.preview_segment).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(bottom_frame, text="切割视频", command=self.cut_video).pack(side=tk.LEFT)
        
        main_frame.columnconfigure(0, weight=1)
        main_frame.rowconfigure(1, weight=1)
    
    def open_video(self):
        file_path = filedialog.askopenfilename(
            filetypes=[("视频文件", "*.mp4 *.avi *.mov *.mkv *.wmv"), ("所有文件", "*.*")]
        )
        
        if file_path:
            self.video_path = file_path
            self.file_label.config(text=os.path.basename(file_path))
            
            self.cap = cv2.VideoCapture(file_path)
            if not self.cap.isOpened():
                messagebox.showerror("错误", "无法打开视频文件")
                return
            
            self.total_frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
            self.fps = self.cap.get(cv2.CAP_PROP_FPS)
            self.duration = self.total_frames / self.fps
            
            self.progress_bar.config(to=self.duration)
            self.end_time_var.set(self.format_time(self.duration))
            
            self.show_frame(0)
    
    def format_time(self, seconds):
        hours = int(seconds // 3600)
        minutes = int((seconds % 3600) // 60)
        secs = int(seconds % 60)
        return f"{hours:02d}:{minutes:02d}:{secs:02d}"
    
    def show_frame(self, frame_num):
        if not self.cap:
            return
        
        self.cap.set(cv2.CAP_PROP_POS_FRAMES, frame_num)
        ret, frame = self.cap.read()
        
        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame = cv2.resize(frame, (640, 360))
            
            img = Image.fromarray(frame)
            imgtk = ImageTk.PhotoImage(image=img)
            
            self.canvas.create_image(0, 0, anchor=tk.NW, image=imgtk)
            self.canvas.image = imgtk
            
            self.current_frame = frame_num
            current_time = frame_num / self.fps
            self.progress_var.set(current_time)
            self.time_label.config(text=f"{self.format_time(current_time)} / {self.format_time(self.duration)}")
    
    def play_video(self):
        if not self.cap:
            return
        
        self.is_playing = True
        threading.Thread(target=self._play_thread, daemon=True).start()
    
    def _play_thread(self):
        while self.is_playing and self.current_frame < self.total_frames - 1:
            self.show_frame(self.current_frame)
            self.current_frame += 1
            time.sleep(1 / self.fps)
        
        self.is_playing = False
    
    def pause_video(self):
        self.is_playing = False
    
    def on_progress_change(self, value):
        if not self.cap:
            return
        
        frame_num = int(float(value) * self.fps)
        self.show_frame(frame_num)
    
    def set_current_as_start(self):
        current_time = self.current_frame / self.fps
        self.start_time_var.set(self.format_time(current_time))
    
    def set_current_as_end(self):
        current_time = self.current_frame / self.fps
        self.end_time_var.set(self.format_time(current_time))
    
    def parse_time(self, time_str):
        try:
            parts = time_str.split(":")
            if len(parts) == 3:
                hours, minutes, seconds = map(int, parts)
                return hours * 3600 + minutes * 60 + seconds
            elif len(parts) == 2:
                minutes, seconds = map(int, parts)
                return minutes * 60 + seconds
            else:
                return float(parts[0])
        except:
            return 0
    
    def preview_segment(self):
        if not self.cap:
            messagebox.showwarning("警告", "请先打开视频文件")
            return
        
        start_time = self.parse_time(self.start_time_var.get())
        end_time = self.parse_time(self.end_time_var.get())
        
        if start_time >= end_time:
            messagebox.showerror("错误", "开始时间必须小于结束时间")
            return
        
        if end_time > self.duration:
            messagebox.showerror("错误", "结束时间不能超过视频总时长")
            return
        
        start_frame = int(start_time * self.fps)
        self.show_frame(start_frame)
    
    def cut_video(self):
        if not self.cap:
            messagebox.showwarning("警告", "请先打开视频文件")
            return
        
        start_time = self.parse_time(self.start_time_var.get())
        end_time = self.parse_time(self.end_time_var.get())
        
        if start_time >= end_time:
            messagebox.showerror("错误", "开始时间必须小于结束时间")
            return
        
        if end_time > self.duration:
            messagebox.showerror("错误", "结束时间不能超过视频总时长")
            return
        
        save_path = filedialog.asksaveasfilename(
            defaultextension=".mp4",
            filetypes=[("MP4文件", "*.mp4"), ("AVI文件", "*.avi"), ("所有文件", "*.*")]
        )
        
        if not save_path:
            return
        
        threading.Thread(target=self._cut_video_thread, args=(start_time, end_time, save_path), daemon=True).start()
    
    def _cut_video_thread(self, start_time, end_time, save_path):
        try:
            cap = cv2.VideoCapture(self.video_path)
            
            # 尝试不同的编解码器
            fourcc_options = ['mp4v', 'XVID', 'MJPG', 'H264']
            fps = self.fps
            width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            
            out = None
            for codec in fourcc_options:
                try:
                    fourcc = cv2.VideoWriter_fourcc(*codec)
                    out = cv2.VideoWriter(save_path, fourcc, fps, (width, height))
                    if out.isOpened():
                        break
                    else:
                        out.release()
                except:
                    if out:
                        out.release()
                    continue
            
            if not out or not out.isOpened():
                # 如果所有编解码器都失败，使用默认设置
                out = cv2.VideoWriter(save_path, 0x00000021, fps, (width, height))
            
            start_frame = int(start_time * fps)
            end_frame = int(end_time * fps)
            
            cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
            
            for frame_num in range(start_frame, end_frame):
                ret, frame = cap.read()
                if not ret:
                    break
                out.write(frame)
            
            cap.release()
            out.release()
            
            self.root.after(0, lambda: messagebox.showinfo("完成", f"视频切割完成！\n保存路径: {save_path}"))
            
        except Exception as e:
            self.root.after(0, lambda: messagebox.showerror("错误", f"切割失败: {str(e)}"))

if __name__ == "__main__":
    root = tk.Tk()
    app = VideoCutter(root)
    root.mainloop()